/*
 * jFrGotha.java
 *
 */
package gotha;

import java.net.URISyntaxException;
import java.rmi.*;

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;
import java.nio.channels.*;
import java.text.*;
import java.util.prefs.*;

/**
 *
 * @author  Luc Vannier
 */
public class JFrGotha extends javax.swing.JFrame {

    private static final long REFRESH_DELAY = 2000;
    private long lastComponentsUpdateTime = 0;
    public static final int BIG_FRAME_WIDTH = 1000;
    public static final int BIG_FRAME_HEIGHT = 700;
    public static final int MEDIUM_FRAME_WIDTH = 796;
    public static final int MEDIUM_FRAME_HEIGHT = 553;
    private static final int PL_COL = 0;
    private static final int NAME_COL = 1;
    private static final int RANK_COL = 2;
    private static final int NBW_COL = 3;
    private static final int ROUND0_RESULT_COL = 4;
    private static final int CRIT0_COL = ROUND0_RESULT_COL + Gotha.MAX_NUMBER_OF_ROUNDS;
    /** should stay between 0 and 9 */
    private static final int MAX_NUMBER_OF_RECENT_TOURNAMENTS = 4;
    private int displayedRoundNumber = 0;
    private boolean bDisplayTemporaryParameterSet = false;
    private int[] displayedCriteria = new int[PlacementParameterSet.PLA_MAX_NUMBER_OF_CRITERIA];
    /**  current Tournament */
    private TournamentInterface tournament = null;
    private long lastDisplayedStandingsUpdateTime = 0;
    private ControlPanelTableCellRenderer cpTableCellRenderer = new ControlPanelTableCellRenderer();

    /**
     * Creates new form jFrGotha
     */
    public JFrGotha(TournamentInterface tournament) throws RemoteException {
        this.tournament = tournament;

        initComponents();

        if (Gotha.runningMode == Gotha.RUNNING_MODE_SAL || Gotha.runningMode == Gotha.RUNNING_MODE_SRV) {
            ArrayList<String> alRT = getRecentTournamentsList();
            if (alRT.size() >= 1) {
                try {
                    File f = new File(alRT.get(0));
                    if (f.canRead()) {
                        openTournament(f);
                    } else {
                        System.out.println("" + f.getName() + " cannot be read");
                    }
                } catch (FileNotFoundException ex) {
                    Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        customInitComponents();
        setVisible(true);

        setupRefreshTimer();
    }

    private void setupRefreshTimer() {
        ActionListener taskPerformer = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent evt) {
                if (tournament == null) {
                    return;
                }
                try {
                    boolean b = tournament.clockIn(Gotha.clientName);
                    if (!b && Gotha.runningMode == Gotha.RUNNING_MODE_CLI) {
                        JOptionPane.showMessageDialog(null, "Connection to Server has been reset for current tournament\nOpenGotha will stop",
                                "Message", JOptionPane.ERROR_MESSAGE);
                        System.exit(0);

                    }
                    if (tournament.getLastTournamentModificationTime() > lastComponentsUpdateTime) {
                        updateAllViews();
                    }
                } catch (RemoteException ex) {
                    JOptionPane.showMessageDialog(null, "Connection to Server has been reset\nOpenGotha will stop",
                            "Message", JOptionPane.ERROR_MESSAGE);
                    System.exit(0);

//                    Logger.getLogger(JFrGamesResults.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        };
        new javax.swing.Timer((int) REFRESH_DELAY, taskPerformer).start();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        grpSystem = new javax.swing.ButtonGroup();
        dlgNew = new javax.swing.JDialog();
        pnlSystem = new javax.swing.JPanel();
        rdbMacMahon = new javax.swing.JRadioButton();
        rdbSwiss = new javax.swing.JRadioButton();
        rdbSwissCat = new javax.swing.JRadioButton();
        jLabel13 = new javax.swing.JLabel();
        txfNumberOfRounds = new javax.swing.JTextField();
        pnlIdentification = new javax.swing.JPanel();
        jLabel8 = new javax.swing.JLabel();
        txfShortName = new javax.swing.JTextField();
        jLabel10 = new javax.swing.JLabel();
        txfName = new javax.swing.JTextField();
        jLabel11 = new javax.swing.JLabel();
        txfLocation = new javax.swing.JTextField();
        jLabel12 = new javax.swing.JLabel();
        txfBeginDate = new javax.swing.JTextField();
        btnDlgNewOK = new javax.swing.JButton();
        btnDlgNewCancel = new javax.swing.JButton();
        btnHelp = new javax.swing.JButton();
        grpPS = new javax.swing.ButtonGroup();
        dlgImportXML = new javax.swing.JDialog();
        btnDlgImportXMLOK = new javax.swing.JButton();
        btnDlgImportXMLCancel = new javax.swing.JButton();
        pnlObjectsToImport = new javax.swing.JPanel();
        chkPlayers = new javax.swing.JCheckBox();
        chkGames = new javax.swing.JCheckBox();
        chkTournamentParameters = new javax.swing.JCheckBox();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        tpnGotha = new javax.swing.JTabbedPane();
        pnlWelcome = new javax.swing.JPanel();
        lblTournamentPicture = new javax.swing.JLabel();
        lblSoftpedia = new javax.swing.JLabel();
        lblFlowChart = new javax.swing.JLabel();
        pnlControlPanel = new javax.swing.JPanel();
        pnlIntControlPanel = new javax.swing.JPanel();
        scpControlPanel = new javax.swing.JScrollPane();
        tblControlPanel = new javax.swing.JTable();
        lblWarningPRE = new javax.swing.JLabel();
        pnlStandings = new javax.swing.JPanel();
        pnlIntStandings = new javax.swing.JPanel();
        lblStandingsAfter = new javax.swing.JLabel();
        pnlPS = new javax.swing.JPanel();
        rdbCurrentPS = new javax.swing.JRadioButton();
        rdbTemporaryPS = new javax.swing.JRadioButton();
        cbxCrit1 = new javax.swing.JComboBox();
        jLabel3 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        cbxCrit2 = new javax.swing.JComboBox();
        jLabel5 = new javax.swing.JLabel();
        cbxCrit3 = new javax.swing.JComboBox();
        jLabel6 = new javax.swing.JLabel();
        cbxCrit4 = new javax.swing.JComboBox();
        scpStandings = new javax.swing.JScrollPane();
        tblStandings = new javax.swing.JTable();
        btnPrint = new javax.swing.JButton();
        lblUpdateTime = new javax.swing.JLabel();
        spnRoundNumber = new javax.swing.JSpinner();
        jLabel7 = new javax.swing.JLabel();
        txfSearchPlayer = new javax.swing.JTextField();
        btnSearch = new javax.swing.JButton();
        mnuMain = new javax.swing.JMenuBar();
        mnuTournament = new javax.swing.JMenu();
        mniNew = new javax.swing.JMenuItem();
        mniOpen = new javax.swing.JMenuItem();
        mnuOpenRecent = new javax.swing.JMenu();
        mniSave = new javax.swing.JMenuItem();
        mniSaveAs = new javax.swing.JMenuItem();
        mniClose = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JSeparator();
        mnuImport = new javax.swing.JMenu();
        mniImportH9 = new javax.swing.JMenuItem();
        mniImportTou = new javax.swing.JMenuItem();
        mniImportXML = new javax.swing.JMenuItem();
        mnuExport = new javax.swing.JMenu();
        mniExportH9 = new javax.swing.JMenuItem();
        mniExportTou = new javax.swing.JMenuItem();
        mniExportHTML = new javax.swing.JMenuItem();
        mniExportPlayersCSV = new javax.swing.JMenuItem();
        mniExportXML = new javax.swing.JMenuItem();
        jSeparator2 = new javax.swing.JSeparator();
        mniPageSetup = new javax.swing.JMenuItem();
        mniPrint = new javax.swing.JMenuItem();
        jSeparator3 = new javax.swing.JSeparator();
        mniExit = new javax.swing.JMenuItem();
        jSeparator4 = new javax.swing.JSeparator();
        mniBuildTestTournament = new javax.swing.JMenuItem();
        mnuPlayers = new javax.swing.JMenu();
        mniPlayersManager = new javax.swing.JMenuItem();
        mniPlayersQuickCheck = new javax.swing.JMenuItem();
        mniMMGroups = new javax.swing.JMenuItem();
        mnuGames = new javax.swing.JMenu();
        mniPair = new javax.swing.JMenuItem();
        mniResults = new javax.swing.JMenuItem();
        mniRR = new javax.swing.JMenuItem();
        mnuOptions = new javax.swing.JMenu();
        mniTournamentOptions = new javax.swing.JMenuItem();
        mniGamesOptions = new javax.swing.JMenuItem();
        mnuTools = new javax.swing.JMenu();
        mniRMI = new javax.swing.JMenuItem();
        mnuHelp = new javax.swing.JMenu();
        mniOpenGothaHelp = new javax.swing.JMenuItem();
        mniHelpAbout = new javax.swing.JMenuItem();

        dlgNew.getContentPane().setLayout(null);

        pnlSystem.setBorder(javax.swing.BorderFactory.createTitledBorder("System"));
        pnlSystem.setLayout(null);

        grpPS.add(rdbMacMahon);
        rdbMacMahon.setFont(new java.awt.Font("Tahoma", 0, 10));
        rdbMacMahon.setSelected(true);
        rdbMacMahon.setText("Mac-Mahon");
        rdbMacMahon.setToolTipText("Players will be paired according to their rank! The winner will be the strongest");
        rdbMacMahon.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        rdbMacMahon.setMargin(new java.awt.Insets(0, 0, 0, 0));
        pnlSystem.add(rdbMacMahon);
        rdbMacMahon.setBounds(20, 30, 170, 13);

        grpPS.add(rdbSwiss);
        rdbSwiss.setFont(new java.awt.Font("Tahoma", 0, 10));
        rdbSwiss.setText("Swiss");
        rdbSwiss.setToolTipText("Good system for championships");
        rdbSwiss.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        rdbSwiss.setMargin(new java.awt.Insets(0, 0, 0, 0));
        pnlSystem.add(rdbSwiss);
        rdbSwiss.setBounds(20, 60, 170, 13);

        grpPS.add(rdbSwissCat);
        rdbSwissCat.setFont(new java.awt.Font("Tahoma", 0, 10));
        rdbSwissCat.setText("Swiss with categories");
        rdbSwissCat.setToolTipText("Because of possible games with a big rank difference, this system is not usually recommended");
        rdbSwissCat.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        rdbSwissCat.setEnabled(false);
        rdbSwissCat.setMargin(new java.awt.Insets(0, 0, 0, 0));
        pnlSystem.add(rdbSwissCat);
        rdbSwissCat.setBounds(20, 90, 170, 13);

        jLabel13.setFont(new java.awt.Font("Tahoma", 0, 10));
        jLabel13.setText("Number of rounds");
        pnlSystem.add(jLabel13);
        jLabel13.setBounds(20, 130, 120, 13);

        txfNumberOfRounds.setText("0");
        pnlSystem.add(txfNumberOfRounds);
        txfNumberOfRounds.setBounds(160, 130, 30, 20);

        dlgNew.getContentPane().add(pnlSystem);
        pnlSystem.setBounds(10, 10, 220, 180);

        pnlIdentification.setBorder(javax.swing.BorderFactory.createTitledBorder("Identification"));
        pnlIdentification.setLayout(null);

        jLabel8.setText("Short name");
        pnlIdentification.add(jLabel8);
        jLabel8.setBounds(10, 60, 80, 14);

        txfShortName.setText("Key name of the tournament");
        pnlIdentification.add(txfShortName);
        txfShortName.setBounds(90, 60, 180, 20);

        jLabel10.setText("Name");
        pnlIdentification.add(jLabel10);
        jLabel10.setBounds(10, 30, 80, 14);

        txfName.setText("Tournament name");
        pnlIdentification.add(txfName);
        txfName.setBounds(90, 30, 180, 20);

        jLabel11.setText("Location");
        pnlIdentification.add(jLabel11);
        jLabel11.setBounds(10, 90, 80, 14);

        txfLocation.setText("Location name");
        pnlIdentification.add(txfLocation);
        txfLocation.setBounds(90, 90, 180, 20);

        jLabel12.setText("Date");
        pnlIdentification.add(jLabel12);
        jLabel12.setBounds(10, 120, 80, 14);

        txfBeginDate.setText("yyyy-mm-dd");
        pnlIdentification.add(txfBeginDate);
        txfBeginDate.setBounds(90, 120, 110, 20);

        dlgNew.getContentPane().add(pnlIdentification);
        pnlIdentification.setBounds(240, 10, 280, 180);

        btnDlgNewOK.setText("OK");
        btnDlgNewOK.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnDlgNewOKActionPerformed(evt);
            }
        });
        dlgNew.getContentPane().add(btnDlgNewOK);
        btnDlgNewOK.setBounds(250, 220, 120, 30);

        btnDlgNewCancel.setText("Cancel");
        btnDlgNewCancel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnDlgNewCancelActionPerformed(evt);
            }
        });
        dlgNew.getContentPane().add(btnDlgNewCancel);
        btnDlgNewCancel.setBounds(380, 220, 130, 30);

        btnHelp.setIcon(new javax.swing.ImageIcon(getClass().getResource("/gotha/gothalogo16.jpg"))); // NOI18N
        btnHelp.setText("help");
        btnHelp.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnHelpActionPerformed(evt);
            }
        });
        dlgNew.getContentPane().add(btnHelp);
        btnHelp.setBounds(120, 220, 110, 30);

        dlgImportXML.getContentPane().setLayout(null);

        btnDlgImportXMLOK.setText("OK");
        btnDlgImportXMLOK.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnDlgImportXMLOKActionPerformed(evt);
            }
        });
        dlgImportXML.getContentPane().add(btnDlgImportXMLOK);
        btnDlgImportXMLOK.setBounds(160, 250, 120, 23);

        btnDlgImportXMLCancel.setText("Cancel");
        btnDlgImportXMLCancel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnDlgImportXMLCancelActionPerformed(evt);
            }
        });
        dlgImportXML.getContentPane().add(btnDlgImportXMLCancel);
        btnDlgImportXMLCancel.setBounds(320, 250, 120, 23);

        pnlObjectsToImport.setBorder(javax.swing.BorderFactory.createTitledBorder("Objects to Import"));
        pnlObjectsToImport.setLayout(null);

        chkPlayers.setFont(new java.awt.Font("Tahoma", 0, 10));
        chkPlayers.setSelected(true);
        chkPlayers.setText("Players");
        pnlObjectsToImport.add(chkPlayers);
        chkPlayers.setBounds(20, 30, 140, 21);

        chkGames.setFont(new java.awt.Font("Tahoma", 0, 10));
        chkGames.setSelected(true);
        chkGames.setText("Games");
        pnlObjectsToImport.add(chkGames);
        chkGames.setBounds(20, 60, 140, 21);

        chkTournamentParameters.setFont(new java.awt.Font("Tahoma", 0, 10));
        chkTournamentParameters.setText("Tournament Parameters");
        pnlObjectsToImport.add(chkTournamentParameters);
        chkTournamentParameters.setBounds(20, 100, 140, 21);

        dlgImportXML.getContentPane().add(pnlObjectsToImport);
        pnlObjectsToImport.setBounds(200, 20, 200, 150);

        jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel1.setText("Importation will merge information from xml file with information in current tournament.");
        jLabel1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        dlgImportXML.getContentPane().add(jLabel1);
        jLabel1.setBounds(20, 180, 580, 14);

        jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel2.setText("Before proceeding, make sure to have a good backup.");
        jLabel2.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        dlgImportXML.getContentPane().add(jLabel2);
        jLabel2.setBounds(20, 200, 580, 14);

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Gotha");
        setIconImage(getIconImage());
        setResizable(false);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosed(java.awt.event.WindowEvent evt) {
                formWindowClosed(evt);
            }
        });
        getContentPane().setLayout(null);

        tpnGotha.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                tpnGothaStateChanged(evt);
            }
        });

        pnlWelcome.setLayout(null);

        lblTournamentPicture.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblTournamentPicture.setIcon(new javax.swing.ImageIcon(getClass().getResource("/gotha/Groningen400X266.jpg"))); // NOI18N
        pnlWelcome.add(lblTournamentPicture);
        lblTournamentPicture.setBounds(124, 5, 546, 298);

        lblSoftpedia.setIcon(new javax.swing.ImageIcon(getClass().getResource("/gotha/softpedia_free_award_f.gif"))); // NOI18N
        lblSoftpedia.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                lblSoftpediaMouseClicked(evt);
            }
        });
        pnlWelcome.add(lblSoftpedia);
        lblSoftpedia.setBounds(780, 470, 160, 120);

        lblFlowChart.setBackground(new java.awt.Color(255, 255, 255));
        lblFlowChart.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblFlowChart.setIcon(new javax.swing.ImageIcon(getClass().getResource("/gotha/flowchart.jpg"))); // NOI18N
        pnlWelcome.add(lblFlowChart);
        lblFlowChart.setBounds(38, 316, 724, 200);

        tpnGotha.addTab("Welcome", pnlWelcome);

        pnlControlPanel.setLayout(null);

        pnlIntControlPanel.setLayout(null);

        scpControlPanel.setBorder(null);

        tblControlPanel.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Round", "Participants", "Assigned players", "Entered results"
            }
        ) {
            boolean[] canEdit = new boolean [] {
                false, false, false, false
            };

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        tblControlPanel.setEnabled(false);
        tblControlPanel.setRowSelectionAllowed(false);
        scpControlPanel.setViewportView(tblControlPanel);

        pnlIntControlPanel.add(scpControlPanel);
        scpControlPanel.setBounds(180, 50, 370, 180);

        lblWarningPRE.setForeground(new java.awt.Color(255, 0, 0));
        pnlIntControlPanel.add(lblWarningPRE);
        lblWarningPRE.setBounds(10, 270, 510, 0);

        pnlControlPanel.add(pnlIntControlPanel);
        pnlIntControlPanel.setBounds(0, 0, 790, 570);

        tpnGotha.addTab("Control Panel", pnlControlPanel);

        pnlStandings.setLayout(null);

        pnlIntStandings.setLayout(null);

        lblStandingsAfter.setText("Standings after round");
        pnlIntStandings.add(lblStandingsAfter);
        lblStandingsAfter.setBounds(10, 40, 130, 14);

        pnlPS.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Placement parameter set"));
        pnlPS.setLayout(null);

        grpPS.add(rdbCurrentPS);
        rdbCurrentPS.setFont(new java.awt.Font("Tahoma", 0, 10));
        rdbCurrentPS.setText("use current set");
        rdbCurrentPS.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        rdbCurrentPS.setMargin(new java.awt.Insets(0, 0, 0, 0));
        rdbCurrentPS.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rdbCurrentPSActionPerformed(evt);
            }
        });
        pnlPS.add(rdbCurrentPS);
        rdbCurrentPS.setBounds(10, 20, 170, 13);

        grpPS.add(rdbTemporaryPS);
        rdbTemporaryPS.setFont(new java.awt.Font("Tahoma", 0, 10));
        rdbTemporaryPS.setText("use temporary set");
        rdbTemporaryPS.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        rdbTemporaryPS.setMargin(new java.awt.Insets(0, 0, 0, 0));
        rdbTemporaryPS.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rdbTemporaryPSActionPerformed(evt);
            }
        });
        pnlPS.add(rdbTemporaryPS);
        rdbTemporaryPS.setBounds(10, 40, 170, 13);

        cbxCrit1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        cbxCrit1.setEnabled(false);
        cbxCrit1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cbxCrit1ActionPerformed(evt);
            }
        });
        pnlPS.add(cbxCrit1);
        cbxCrit1.setBounds(60, 70, 120, 20);

        jLabel3.setFont(new java.awt.Font("Tahoma", 0, 10));
        jLabel3.setText("Crit 1");
        pnlPS.add(jLabel3);
        jLabel3.setBounds(10, 70, 34, 13);

        jLabel4.setFont(new java.awt.Font("Tahoma", 0, 10));
        jLabel4.setText("Crit 2");
        pnlPS.add(jLabel4);
        jLabel4.setBounds(10, 100, 34, 13);

        cbxCrit2.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        cbxCrit2.setEnabled(false);
        cbxCrit2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cbxCrit2ActionPerformed(evt);
            }
        });
        pnlPS.add(cbxCrit2);
        cbxCrit2.setBounds(60, 100, 120, 20);

        jLabel5.setFont(new java.awt.Font("Tahoma", 0, 10));
        jLabel5.setText("Crit 3");
        pnlPS.add(jLabel5);
        jLabel5.setBounds(10, 130, 34, 13);

        cbxCrit3.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        cbxCrit3.setEnabled(false);
        cbxCrit3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cbxCrit3ActionPerformed(evt);
            }
        });
        pnlPS.add(cbxCrit3);
        cbxCrit3.setBounds(60, 130, 120, 20);

        jLabel6.setFont(new java.awt.Font("Tahoma", 0, 10));
        jLabel6.setText("Crit 4");
        pnlPS.add(jLabel6);
        jLabel6.setBounds(10, 160, 34, 13);

        cbxCrit4.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        cbxCrit4.setEnabled(false);
        cbxCrit4.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cbxCrit4ActionPerformed(evt);
            }
        });
        pnlPS.add(cbxCrit4);
        cbxCrit4.setBounds(60, 160, 120, 20);

        pnlIntStandings.add(pnlPS);
        pnlPS.setBounds(0, 70, 190, 210);

        tblStandings.setFont(new java.awt.Font("Arial", 0, 10));
        tblStandings.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null},
                {null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null},
                {null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null},
                {null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null}
            },
            new String [] {
                "Pl", "Name", "Rank", "Score", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", "R16", "R17", "R18", "R19", "R20", "crit1", "crit2", "crit3", "crit4", "crit5", "crit6"
            }
        ));
        tblStandings.setEnabled(false);
        tblStandings.setRowSelectionAllowed(false);
        scpStandings.setViewportView(tblStandings);

        pnlIntStandings.add(scpStandings);
        scpStandings.setBounds(190, 10, 600, 500);

        btnPrint.setText("Print...");
        btnPrint.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnPrintActionPerformed(evt);
            }
        });
        pnlIntStandings.add(btnPrint);
        btnPrint.setBounds(0, 480, 190, 30);

        lblUpdateTime.setText("updated at : ");
        pnlIntStandings.add(lblUpdateTime);
        lblUpdateTime.setBounds(10, 300, 170, 14);

        spnRoundNumber.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                spnRoundNumberStateChanged(evt);
            }
        });
        pnlIntStandings.add(spnRoundNumber);
        spnRoundNumber.setBounds(140, 30, 40, 30);

        jLabel7.setText("Search for a player");
        pnlIntStandings.add(jLabel7);
        jLabel7.setBounds(10, 360, 130, 14);
        pnlIntStandings.add(txfSearchPlayer);
        txfSearchPlayer.setBounds(10, 380, 130, 20);

        btnSearch.setText("Search");
        btnSearch.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSearchActionPerformed(evt);
            }
        });
        pnlIntStandings.add(btnSearch);
        btnSearch.setBounds(10, 410, 130, 23);

        pnlStandings.add(pnlIntStandings);
        pnlIntStandings.setBounds(0, 0, 790, 570);

        tpnGotha.addTab("Standings", pnlStandings);

        getContentPane().add(tpnGotha);
        tpnGotha.setBounds(0, 0, 970, 640);

        mnuMain.setFont(new java.awt.Font("Arial", 0, 11));

        mnuTournament.setText("Tournament");
        mnuTournament.setFont(new java.awt.Font("Arial", 0, 11));

        mniNew.setFont(new java.awt.Font("Arial", 0, 11));
        mniNew.setText("New...");
        mniNew.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniNewActionPerformed(evt);
            }
        });
        mnuTournament.add(mniNew);

        mniOpen.setFont(new java.awt.Font("Arial", 0, 11));
        mniOpen.setText("Open...");
        mniOpen.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniOpenActionPerformed(evt);
            }
        });
        mnuTournament.add(mniOpen);

        mnuOpenRecent.setText("Open Recent ... ");
        mnuOpenRecent.setFont(new java.awt.Font("Arial", 0, 11));
        mnuTournament.add(mnuOpenRecent);

        mniSave.setFont(new java.awt.Font("Arial", 0, 11));
        mniSave.setText("Save");
        mniSave.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniSaveActionPerformed(evt);
            }
        });
        mnuTournament.add(mniSave);

        mniSaveAs.setFont(new java.awt.Font("Arial", 0, 11));
        mniSaveAs.setText("Save as ...");
        mniSaveAs.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniSaveAsActionPerformed(evt);
            }
        });
        mnuTournament.add(mniSaveAs);

        mniClose.setFont(new java.awt.Font("Arial", 0, 11));
        mniClose.setText("Close");
        mniClose.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniCloseActionPerformed(evt);
            }
        });
        mnuTournament.add(mniClose);
        mnuTournament.add(jSeparator1);

        mnuImport.setText("Import ...");
        mnuImport.setFont(new java.awt.Font("Arial", 0, 11));

        mniImportH9.setFont(new java.awt.Font("Arial", 0, 11));
        mniImportH9.setText("Import Players and Games from h9 file");
        mniImportH9.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniImportH9ActionPerformed(evt);
            }
        });
        mnuImport.add(mniImportH9);

        mniImportTou.setFont(new java.awt.Font("Arial", 0, 11));
        mniImportTou.setText("Import Players and Games from Tou file");
        mniImportTou.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniImportTouActionPerformed(evt);
            }
        });
        mnuImport.add(mniImportTou);

        mniImportXML.setFont(new java.awt.Font("Arial", 0, 11));
        mniImportXML.setText("Import tournament from XML File");
        mniImportXML.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniImportXMLActionPerformed(evt);
            }
        });
        mnuImport.add(mniImportXML);

        mnuTournament.add(mnuImport);

        mnuExport.setText("Export");
        mnuExport.setFont(new java.awt.Font("Arial", 0, 11));

        mniExportH9.setFont(new java.awt.Font("Arial", 0, 11));
        mniExportH9.setText("Results for EGF rating-list");
        mniExportH9.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniExportH9ActionPerformed(evt);
            }
        });
        mnuExport.add(mniExportH9);

        mniExportTou.setFont(new java.awt.Font("Arial", 0, 11));
        mniExportTou.setText("Results for FFG rating-list");
        mniExportTou.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniExportTouActionPerformed(evt);
            }
        });
        mnuExport.add(mniExportTou);

        mniExportHTML.setFont(new java.awt.Font("Arial", 0, 11));
        mniExportHTML.setText("Ready-To-Publish Results in HTML format");
        mniExportHTML.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniExportHTMLActionPerformed(evt);
            }
        });
        mnuExport.add(mniExportHTML);

        mniExportPlayersCSV.setFont(new java.awt.Font("Arial", 0, 11));
        mniExportPlayersCSV.setText("Players in CSV format");
        mniExportPlayersCSV.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniExportPlayersCSVActionPerformed(evt);
            }
        });
        mnuExport.add(mniExportPlayersCSV);

        mniExportXML.setFont(new java.awt.Font("Arial", 0, 11));
        mniExportXML.setText("Tournament in XML Format");
        mniExportXML.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniExportXMLActionPerformed(evt);
            }
        });
        mnuExport.add(mniExportXML);

        mnuTournament.add(mnuExport);
        mnuTournament.add(jSeparator2);

        mniPageSetup.setFont(new java.awt.Font("Arial", 0, 11));
        mniPageSetup.setText("Page setup...");
        mniPageSetup.setEnabled(false);
        mnuTournament.add(mniPageSetup);

        mniPrint.setFont(new java.awt.Font("Arial", 0, 11));
        mniPrint.setText("Print...");
        mniPrint.setEnabled(false);
        mnuTournament.add(mniPrint);
        mnuTournament.add(jSeparator3);

        mniExit.setFont(new java.awt.Font("Arial", 0, 11));
        mniExit.setText("Exit");
        mniExit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniExitActionPerformed(evt);
            }
        });
        mnuTournament.add(mniExit);
        mnuTournament.add(jSeparator4);

        mniBuildTestTournament.setFont(new java.awt.Font("Arial", 0, 11));
        mniBuildTestTournament.setText("Build test tournament");
        mniBuildTestTournament.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniBuildTestTournamentActionPerformed(evt);
            }
        });
        mnuTournament.add(mniBuildTestTournament);

        mnuMain.add(mnuTournament);

        mnuPlayers.setText("Players");
        mnuPlayers.setFont(new java.awt.Font("Arial", 0, 11));

        mniPlayersManager.setFont(new java.awt.Font("Arial", 0, 11));
        mniPlayersManager.setText("Players Manager");
        mniPlayersManager.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniPlayersManagerActionPerformed(evt);
            }
        });
        mnuPlayers.add(mniPlayersManager);

        mniPlayersQuickCheck.setFont(new java.awt.Font("Arial", 0, 11));
        mniPlayersQuickCheck.setText("Players Quick check");
        mniPlayersQuickCheck.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniPlayersQuickCheckActionPerformed(evt);
            }
        });
        mnuPlayers.add(mniPlayersQuickCheck);

        mniMMGroups.setFont(new java.awt.Font("Arial", 0, 11));
        mniMMGroups.setText("Mac-Mahon groups");
        mniMMGroups.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniMMGroupsActionPerformed(evt);
            }
        });
        mnuPlayers.add(mniMMGroups);

        mnuMain.add(mnuPlayers);

        mnuGames.setText("Games");
        mnuGames.setFont(new java.awt.Font("Arial", 0, 11));

        mniPair.setFont(new java.awt.Font("Arial", 0, 11));
        mniPair.setText("Pair");
        mniPair.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniPairActionPerformed(evt);
            }
        });
        mnuGames.add(mniPair);

        mniResults.setFont(new java.awt.Font("Arial", 0, 11));
        mniResults.setText("Results");
        mniResults.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniResultsActionPerformed(evt);
            }
        });
        mnuGames.add(mniResults);

        mniRR.setFont(new java.awt.Font("Arial", 0, 11));
        mniRR.setText("Round-robin");
        mniRR.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniRRActionPerformed(evt);
            }
        });
        mnuGames.add(mniRR);

        mnuMain.add(mnuGames);

        mnuOptions.setText("Options");
        mnuOptions.setFont(new java.awt.Font("Arial", 0, 11));

        mniTournamentOptions.setFont(new java.awt.Font("Arial", 0, 11));
        mniTournamentOptions.setText("Tournament Options");
        mniTournamentOptions.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniTournamentOptionsActionPerformed(evt);
            }
        });
        mnuOptions.add(mniTournamentOptions);

        mniGamesOptions.setFont(new java.awt.Font("Arial", 0, 11));
        mniGamesOptions.setText("Games Options");
        mniGamesOptions.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniGamesOptionsActionPerformed(evt);
            }
        });
        mnuOptions.add(mniGamesOptions);

        mnuMain.add(mnuOptions);

        mnuTools.setText("Tools");
        mnuTools.setFont(new java.awt.Font("Arial", 0, 11));

        mniRMI.setFont(new java.awt.Font("Arial", 0, 11));
        mniRMI.setText("RMI Manager");
        mniRMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniRMIActionPerformed(evt);
            }
        });
        mnuTools.add(mniRMI);

        mnuMain.add(mnuTools);

        mnuHelp.setText("Help");
        mnuHelp.setFont(new java.awt.Font("Arial", 0, 11));

        mniOpenGothaHelp.setFont(new java.awt.Font("Arial", 0, 11));
        mniOpenGothaHelp.setText("OpenGotha help");
        mniOpenGothaHelp.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniOpenGothaHelpActionPerformed(evt);
            }
        });
        mnuHelp.add(mniOpenGothaHelp);

        mniHelpAbout.setFont(new java.awt.Font("Arial", 0, 11));
        mniHelpAbout.setText("About OpenGotha");
        mniHelpAbout.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mniHelpAboutActionPerformed(evt);
            }
        });
        mnuHelp.add(mniHelpAbout);

        mnuMain.add(mnuHelp);

        setJMenuBar(mnuMain);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void mniExportPlayersCSVActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniExportPlayersCSVActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        File f = this.chooseAFileForExport(Gotha.exportDirectory, "csv");
        if (f == null) {
            return;
        }
        // Keep tournamentDirectory
        Gotha.exportDirectory = f.getParentFile();

        ExternalTournamentDocument.generatePlayersCSVFile(tournament, f);
    }//GEN-LAST:event_mniExportPlayersCSVActionPerformed

    private void mniGamesOptionsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniGamesOptionsActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

        try {
            JFrame jfr = new JFrGamesOptions(tournament);
            jfr.setVisible(true);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_mniGamesOptionsActionPerformed

    private void mniExportH9ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniExportH9ActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

        File f = this.chooseAFileForExport(Gotha.exportDirectory, "h9");
        if (f == null) {
            return;
        }
        // Keep tournamentDirectory
        Gotha.exportDirectory = f.getParentFile();

        int response = JOptionPane.showConfirmDialog(this, "Do you want to keep by default results in the exportFile ?"
                + "\nClick Yes to keep them or No to drop them", "Message", JOptionPane.YES_NO_CANCEL_OPTION);

        if (response == JOptionPane.YES_OPTION) {
            ExternalTournamentDocument.generateH9File(tournament, f, true);
        } else if (response == JOptionPane.NO_OPTION) {
            ExternalTournamentDocument.generateH9File(tournament, f, false);
        } else {
            return;
        }
    }//GEN-LAST:event_mniExportH9ActionPerformed

    private void mniExportTouActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniExportTouActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

        TournamentParameterSet tps = null;
        try {
            tps = tournament.getTournamentParameterSet();
        } catch (RemoteException ex) {
            ex.printStackTrace();
            return;
        }
        GeneralParameterSet gps = tps.getGeneralParameterSet();
        if (gps.getStrSize().length() == 0 || gps.getStrTime().length() == 0) {
            JOptionPane.showMessageDialog(this, "Goban size and Thinking time should be documented."
                    + "\nSee Options .. Games menu itemtem", "Message", JOptionPane.ERROR_MESSAGE);
            return;
        }

        File f = this.chooseAFileForExport(Gotha.exportDirectory, "tou");
        if (f == null) {
            return;
        }
        // Keep tournamentDirectory
        Gotha.exportDirectory = f.getParentFile();

//        ExternalTournamentDocument.generateH9File(tournament, f);

        ExternalTournamentDocument.generateTouFile(tournament, f);

    }//GEN-LAST:event_mniExportTouActionPerformed

    private void mniExportHTMLActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniExportHTMLActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

        File f = this.chooseAFileForExport(Gotha.exportHTMLDirectory, "html");
        if (f == null) {
            return;
        }
        Gotha.exportHTMLDirectory = f.getParentFile();
        // If current.css does not exist, create one from default.css
        File currentCSSFile = new File(f.getParentFile(), "current.css");
        if (!currentCSSFile.exists()) {
            try {
                FileChannel srcChannel = new FileInputStream(new File(Gotha.runningDirectory, "exportfiles/html/default.css")).getChannel();
                FileChannel dstChannel = new FileOutputStream(new File(f.getParentFile(), "current.css")).getChannel();

                dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
                srcChannel.close();
                dstChannel.close();
            } catch (IOException e) {
                System.out.println("Exception in css file copying");
            }
        }

        // Do the job
        ExternalTournamentDocument.generateHTMLFile(tournament, f);


    }//GEN-LAST:event_mniExportHTMLActionPerformed

    private void btnPrintActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPrintActionPerformed
        TournamentParameterSet tps = null;
        try {
            tps = tournament.getTournamentParameterSet();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        TournamentParameterSet printTPS = new TournamentParameterSet(tps);
        GeneralParameterSet printGPS = printTPS.getGeneralParameterSet();
        PlacementParameterSet printPPS = printTPS.getPlacementParameterSet();
        printPPS.setPlaCriteria(displayedCriteria);
        ArrayList<ScoredPlayer> alOrderedScoredPlayers = null;

        try {
            alOrderedScoredPlayers = tournament.orderedScoredPlayersList(displayedRoundNumber, printTPS.getPlacementParameterSet());
            // Eliminate non-players
            alOrderedScoredPlayers = this.eliminateNonImpliedPlayers(alOrderedScoredPlayers);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

        TournamentPrinting tpr = new TournamentPrinting(tournament);
        tpr.setRoundNumber(-1);
        tpr.setAlOrderedScoredPlayers(alOrderedScoredPlayers);
        int nbCrit = 0;
        for (int iC = 0; iC < PlacementParameterSet.PLA_MAX_NUMBER_OF_CRITERIA; iC++) {
            if (this.displayedCriteria[iC] == PlacementParameterSet.PLA_CRIT_NUL) {
                continue;
            }
            nbCrit++;
        }
        int[] printCriteria = new int[nbCrit];
        int numCrit = 0;
        for (int iC = 0; iC < PlacementParameterSet.PLA_MAX_NUMBER_OF_CRITERIA; iC++) {
            if (this.displayedCriteria[iC] != PlacementParameterSet.PLA_CRIT_NUL) {
                printCriteria[numCrit++] = displayedCriteria[iC];
            }
        }
        tpr.setPrintCriteria(printCriteria);
        tpr.setRoundNumber(this.displayedRoundNumber);
//        if (printGPS.getNumberOfCategories() > 1)  tpr.makePrinting(TournamentPrinting.TYPE_STANDINGS, TournamentPrinting.SUBTYPE_ST_CAT); 
        if (printPPS.getPlaCriteria()[0] == PlacementParameterSet.PLA_CRIT_CAT && printGPS.getNumberOfCategories() > 1) {
            tpr.makePrinting(TournamentPrinting.TYPE_STANDINGS, TournamentPrinting.SUBTYPE_ST_CAT);
        } else {
            tpr.makePrinting(TournamentPrinting.TYPE_STANDINGS, TournamentPrinting.SUBTYPE_DEFAULT);
        }//GEN-LAST:event_btnPrintActionPerformed
    }

    private void mniMMGroupsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniMMGroupsActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        try {
            if (tournament.tournamentType() != TournamentParameterSet.TYPE_MACMAHON) {
                JOptionPane.showMessageDialog(this, "Mac-Mahon Groups are relevant only in Mac-Mahon tournaments", "Message", JOptionPane.ERROR_MESSAGE);
                return;

            }
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }



        try {
            JFrame jfr = new JFrPlayersMMG(tournament);
            jfr.setVisible(true);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_mniMMGroupsActionPerformed

    private void mniBuildTestTournamentActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniBuildTestTournamentActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        try {
            JFrame jfr = new JFrBuildTestTournament(tournament);
            jfr.setVisible(true);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_mniBuildTestTournamentActionPerformed

    private void mniCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniCloseActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

        // Before carrying on, is there something to save ?
        if (!saveCurrentTournamentIfNecessary()) {
            return;
        }
        closeTournament();
    }//GEN-LAST:event_mniCloseActionPerformed

    private void mniImportTouActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniImportTouActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

        File f = chooseAFile(Gotha.runningDirectory, "tou");
        if (f == null) {
            return;
        }
        ArrayList<Player> alPlayers = new ArrayList<Player>();
        ArrayList<Game> alGames = new ArrayList<Game>();

        try{
            ExternalTournamentDocument.importPlayersAndGamesFromTouFile(f, alPlayers, alGames);
        }
        catch(Exception e){
            JOptionPane.showMessageDialog(this, "Errors occured in reading " + f.getName()
                + "\nImport process has been aborted", "Message", JOptionPane.ERROR_MESSAGE);
            return;
        }

        int nbErrors = 0;
        for (Player p : alPlayers) {
            try {
                tournament.addPlayer(p);
            } catch (RemoteException ex) {
                ex.printStackTrace();
            } catch (TournamentException te) {
                nbErrors++;
                if (nbErrors <= 3) {
                    JOptionPane.showMessageDialog(this, te.getMessage(), "Message", JOptionPane.ERROR_MESSAGE);
                }
                if (nbErrors == 4) {
                    JOptionPane.showMessageDialog(this, "More than 3 errors have been detected", "Message", JOptionPane.ERROR_MESSAGE);
                }
            }
        }
        if (nbErrors > 0) {
            JOptionPane.showMessageDialog(this, "Due to errors on players, games have not been imported", "Message", JOptionPane.ERROR_MESSAGE);
        } else {
            for (Game g : alGames) {
                try {
                    tournament.addGame(g);
                } catch (RemoteException ex) {
                    ex.printStackTrace();
                } catch (TournamentException ex) {
                    ex.printStackTrace();
                }
            }
        }

        try {
            tournament.updateNumberOfRoundsIfNecesary();
        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }

        this.tournamentChanged();

    }//GEN-LAST:event_mniImportTouActionPerformed

    private void btnDlgNewOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDlgNewOKActionPerformed
        int system = TournamentParameterSet.TYPE_MACMAHON;
        if (this.rdbMacMahon.isSelected()) {
            system = TournamentParameterSet.TYPE_MACMAHON;
        }
        if (this.rdbSwiss.isSelected()) {
            system = TournamentParameterSet.TYPE_SWISS;
        }
        if (this.rdbSwissCat.isSelected()) {
            system = TournamentParameterSet.TYPE_SWISSCAT;
        }
        GeneralParameterSet gps = null;
        try {
            gps = new GeneralParameterSet(this.txfShortName.getText(), this.txfName.getText(), this.txfLocation.getText(),
                    new SimpleDateFormat("yyyy-MM-dd").parse(this.txfBeginDate.getText()),
                    new SimpleDateFormat("yyyy-MM-dd").parse(this.txfBeginDate.getText()),
                    new Integer(this.txfNumberOfRounds.getText()).intValue(),
                    1);     // numberOfCategories will be set by initForXX

        } catch (NumberFormatException ex) {
            ex.printStackTrace();
            return;
        } catch (ParseException ex) {
            ex.printStackTrace();
            return;
        }

        HandicapParameterSet hps = new HandicapParameterSet();
        PlacementParameterSet pps = new PlacementParameterSet();
        PairingParameterSet paiPS = new PairingParameterSet();
        switch (system) {
            case TournamentParameterSet.TYPE_MACMAHON:
                gps.initForMM();
                hps.initForMM();
                pps.initForMM();
                paiPS.initForMM();
                break;
            case TournamentParameterSet.TYPE_SWISS:
                gps.initForSwiss();
                hps.initForSwiss();
                pps.initForSwiss();
                paiPS.initForSwiss();
                break;
            case TournamentParameterSet.TYPE_SWISSCAT:
                gps.initForSwissCat();
                hps.initForSwissCat();
                pps.initForSwissCat();
                paiPS.initForSwissCat();
                break;
            default:
                gps.initForMM();
                hps.initForMM();
                pps.initForMM();
                paiPS.initForMM();
        }

        TournamentParameterSet tps = new TournamentParameterSet();
        tps.setGeneralParameterSet(gps);
        tps.setHandicapParameterSet(hps);
        tps.setPlacementParameterSet(pps);
        tps.setPairingParameterSet(paiPS);

        // close previous Tournament if necessary
        closeTournament();

        try {
            tournament = new Tournament(gps.getShortName());
            tournament.setTournamentParameterSet(tps);
            this.lastDisplayedStandingsUpdateTime = 0;
            tournament.setLastTournamentModificationTime(tournament.getCurrentTournamentTime());
            this.tournamentChanged();
            tournament.setChangeSinceLastSave(true);
        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }

        // If we are in Server mode, then rebind tournament
        if (Gotha.runningMode == Gotha.RUNNING_MODE_SRV) {
            GothaRMIServer.addTournament(tournament);
        }

        dlgNew.dispose();
    }//GEN-LAST:event_btnDlgNewOKActionPerformed

    private void btnDlgNewCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDlgNewCancelActionPerformed
        dlgNew.dispose();
    }//GEN-LAST:event_btnDlgNewCancelActionPerformed

    private void mniTournamentOptionsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniTournamentOptionsActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        try {
            JFrame jfr = new JFrTournamentOptions(tournament);
            jfr.setVisible(true);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_mniTournamentOptionsActionPerformed

    private void mniNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniNewActionPerformed
        // Before carrying on, is there something to save ?
        if (!saveCurrentTournamentIfNecessary()) {
            return;
        }
        int w = 540;
        int h = 300;
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        dlgNew.setBounds((dim.width - w) / 2, (dim.height - h) / 2, w, h);
        dlgNew.setTitle("Create a new tournament");
        dlgNew.setIconImage(Gotha.getIconImage());


        this.rdbMacMahon.setSelected(true);
        this.txfNumberOfRounds.setText("5");
        this.txfBeginDate.setText(new java.util.Date().toString());
        this.txfBeginDate.setText((new SimpleDateFormat("yyyy-MM-dd")).format(new java.util.Date()));

        dlgNew.setVisible(true);

    }//GEN-LAST:event_mniNewActionPerformed

    private void tpnGothaStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tpnGothaStateChanged
        JPanel selPanel = (JPanel) tpnGotha.getSelectedComponent();
        if (selPanel == this.pnlStandings) {
            try {
                updateDisplayCriteria();
                updateStandingsComponents();
            } catch (RemoteException ex) {
                ex.printStackTrace();
            }
        }
        if (selPanel == this.pnlControlPanel) {
            try {
                this.updateControlPanel();
            } catch (RemoteException ex) {
                ex.printStackTrace();
            }
        }
    }//GEN-LAST:event_tpnGothaStateChanged

    private void cbxCrit4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbxCrit4ActionPerformed
        // In order to avoid useless updates, ...
        if (!this.cbxCrit4.isEnabled()) {
            return;
        }

        try {
            updateDisplayCriteria();
            updateStandingsComponents();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_cbxCrit4ActionPerformed

    private void cbxCrit3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbxCrit3ActionPerformed
        // In order to avois useless updates, ...
        if (!this.cbxCrit3.isEnabled()) {
            return;
        }

        try {
            updateDisplayCriteria();
            updateStandingsComponents();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_cbxCrit3ActionPerformed

    private void cbxCrit2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbxCrit2ActionPerformed
        // In order to avois useless updates, ...
        if (!this.cbxCrit2.isEnabled()) {
            return;
        }

        try {
            updateDisplayCriteria();
            updateStandingsComponents();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_cbxCrit2ActionPerformed

    private void cbxCrit1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbxCrit1ActionPerformed
        // In order to avois useless updates, ...
        if (!this.cbxCrit1.isEnabled()) {
            return;
        }

        try {
            updateDisplayCriteria();
            updateStandingsComponents();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_cbxCrit1ActionPerformed

    private void rdbTemporaryPSActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rdbTemporaryPSActionPerformed
        try {
            updateDisplayCriteria();
            updateStandingsComponents();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_rdbTemporaryPSActionPerformed

    private void rdbCurrentPSActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rdbCurrentPSActionPerformed
        try {
            updateDisplayCriteria();
            updateStandingsComponents();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_rdbCurrentPSActionPerformed

    private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed
        // Before carrying on, is there something to save ?
        if (!saveCurrentTournamentIfNecessary()) {
            return;
        }

        System.exit(0);
    }//GEN-LAST:event_formWindowClosed

    private void mniExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniExitActionPerformed
        dispose();
    }//GEN-LAST:event_mniExitActionPerformed

    private void mniResultsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniResultsActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        try {
            JFrame jfr = new JFrGamesResults(tournament);
            jfr.setVisible(true);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

    }//GEN-LAST:event_mniResultsActionPerformed

    private void mniPairActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniPairActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        try {
            JFrame jfr = new JFrGamesPair(tournament);
            jfr.setVisible(true);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

    }//GEN-LAST:event_mniPairActionPerformed

    private void mniPlayersQuickCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniPlayersQuickCheckActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        try {
            JFrame jfr = new JFrPlayersQuickCheck(tournament);
            jfr.setVisible(true);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_mniPlayersQuickCheckActionPerformed

    private void customInitComponents() {
        int w = JFrGotha.BIG_FRAME_WIDTH;
        int h = JFrGotha.BIG_FRAME_HEIGHT;

        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((dim.width - w) / 2, 0, w, h);
        setIconImage(Gotha.getIconImage());

        tpnGotha.setBounds(0, 0, w - 6, h - 54);

        int wTP = lblTournamentPicture.getWidth();
        lblTournamentPicture.setLocation((w - wTP) / 2, 5);
        int wFC = lblFlowChart.getWidth();
        lblFlowChart.setLocation((w - wFC) / 2, 316);
//        this.lblSoftpedia.setLocation (w-lblSoftpedia.getWidth(), h - lblSoftpedia.getHeight());
        this.pnlIntControlPanel.setBounds(0, 0, w - 10, h - 30);
        int wCP = scpControlPanel.getWidth();

        this.scpControlPanel.setLocation((w - wCP) / 2, 100);

        this.pnlIntStandings.setBounds(0, 0, w - 10, h - 30);
        this.scpStandings.setBounds(190, 10, w - 200, h - 100);

        updateTitle();

        switch (Gotha.runningMode) {
            case Gotha.RUNNING_MODE_SAL:
                updateOpenRecentMenu();
//                this.mnuTools.setVisible(false);
//                this.mniRMI.setVisible(false);
                break;
            case Gotha.RUNNING_MODE_SRV:
                updateOpenRecentMenu();
                break;
            case Gotha.RUNNING_MODE_CLI:
                this.mniSave.setVisible(false);
                this.mniSaveAs.setVisible(false);
                this.mniNew.setVisible(false);
                this.mniOpen.setVisible(false);
                this.mnuOpenRecent.setVisible(false);
                this.mniClose.setVisible(false);
                this.mnuImport.setVisible(false);
                this.mniBuildTestTournament.setVisible(false);
//                this.mniPair.setVisible(false);
//                this.mniRR.setVisible(false);
                this.mnuTools.setVisible(false);
                this.mniRMI.setVisible(false);
                break;
        }

        try {
            initCriteriaAndStandingsComponents();
            initControlPanelComponents();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Get recent tournaments list from Preferences
     * recent tournaments names are supposed to look like "recentTournamentx" where x = 0 to 9
     */
    private ArrayList<String> getRecentTournamentsList() {
        Preferences prefsRoot = Preferences.userRoot();
        Preferences gothaPrefs = prefsRoot.node("gothaprefs");

        ArrayList<String> alS = new ArrayList<String>();
        for (int numRT = 0; numRT < MAX_NUMBER_OF_RECENT_TOURNAMENTS; numRT++) {
            String strK = "recentTournament" + numRT;
            String strRT = gothaPrefs.get(strK, "");
            if (strRT.compareTo("") != 0) {
                alS.add(strRT);
            }
        }
        return alS;
    }

    /**
     * Insert file name into Preferences
     */
    private void addRecentTournament(String strRecentTournamentFileName) {
        ArrayList<String> alS = getRecentTournamentsList();
        // avoid double
        alS.remove(strRecentTournamentFileName);
        alS.add(0, strRecentTournamentFileName);
        // remove 

        Preferences prefsRoot = Preferences.userRoot();
        Preferences gothaPrefs = prefsRoot.node("gothaprefs");
        int nbRT = Math.min(alS.size(), MAX_NUMBER_OF_RECENT_TOURNAMENTS);
        for (int numRT = 0; numRT < nbRT; numRT++) {
            String strK = "recentTournament" + numRT;
            String strRT = alS.get(numRT);
            gothaPrefs.put(strK, strRT);
        }

        this.updateOpenRecentMenu();
    }

    private void updateOpenRecentMenu() {
        ArrayList<String> alRT = this.getRecentTournamentsList();
        this.mnuOpenRecent.removeAll();
        mnuOpenRecent.setEnabled(true);
        if (alRT.size() == 0) {
            mnuOpenRecent.setEnabled(false);
        }
        for (int numRT = 0; numRT < alRT.size(); numRT++) {
            final String strFile = alRT.get(numRT);
            JMenuItem mni = new JMenuItem(strFile);
            mni.setFont(new java.awt.Font("Arial", 0, 11));
            mni.addActionListener(new java.awt.event.ActionListener() {

                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    try {
                        openTournament(new File(strFile));
                    } catch (FileNotFoundException ex) {
                        JOptionPane.showMessageDialog(null, " File not found", "Message", JOptionPane.ERROR_MESSAGE);
                        // Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            });
            this.mnuOpenRecent.add(mni);
        }
    }

    private void initCriteriaAndStandingsComponents() throws RemoteException {
        cbxCrit1.setModel(new DefaultComboBoxModel(PlacementParameterSet.criteriaLongNames()));
        cbxCrit2.setModel(new DefaultComboBoxModel(PlacementParameterSet.criteriaLongNames()));
        cbxCrit3.setModel(new DefaultComboBoxModel(PlacementParameterSet.criteriaLongNames()));
        cbxCrit4.setModel(new DefaultComboBoxModel(PlacementParameterSet.criteriaLongNames()));

        if (tournament == null) {
            return;
        }
        try {
            displayedRoundNumber = tournament.presumablyCurrentRoundNumber();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

        updateDisplayCriteria();
        DefaultTableModel model = (DefaultTableModel) tblStandings.getModel();
        model.setColumnCount(4 + Gotha.MAX_NUMBER_OF_ROUNDS + PlacementParameterSet.PLA_MAX_NUMBER_OF_CRITERIA);

        // Set the renderer for tblStandings
        tblStandings.setDefaultRenderer(Object.class, new StandingsTableCellRenderer());
        updateStandingsComponents();

    }

    private void updateTitle() {
        String kn = "";
        try {

            if (tournament != null && tournament.isOpen()) {
                kn = tournament.getKeyName();
            }
        } catch (RemoteException ex) {
//            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }

        String titleBeg = Gotha.getGothaVersionnedName() + " ";
//        String titleBeg = "OpenGotha" + " ";
        switch (Gotha.runningMode) {
            case Gotha.RUNNING_MODE_SAL:
                setTitle(titleBeg + kn);
                break;
            case Gotha.RUNNING_MODE_SRV:
                setTitle(titleBeg + "Server." + " " + kn);
                break;
            case Gotha.RUNNING_MODE_CLI:
                setTitle(titleBeg + "Client." + " " + kn + " " + "(Server on " + Gotha.serverName + ")");
        }
    }

    private void initControlPanelComponents() throws RemoteException {
        // Column names in 
        TableColumnModel tcm = this.tblControlPanel.getColumnModel();
        tcm.getColumn(0).setHeaderValue("Round");
        tcm.getColumn(1).setHeaderValue("Participants");
        tcm.getColumn(2).setHeaderValue("Assigned players");
        tcm.getColumn(3).setHeaderValue("Entered results");

        // Set the renderer for tblControlPanel
        tblControlPanel.setDefaultRenderer(Object.class, this.cpTableCellRenderer);

        updateControlPanel();
    }

    private void updateDisplayCriteria() throws RemoteException {
        // update bDisplayTemporaryParameterSet
        bDisplayTemporaryParameterSet = (this.grpPS.getSelection() == this.rdbTemporaryPS.getModel());

        if (bDisplayTemporaryParameterSet) {
            displayedCriteria[0] = PlacementParameterSet.criterionUID((String) cbxCrit1.getModel().getSelectedItem());
            displayedCriteria[1] = PlacementParameterSet.criterionUID((String) cbxCrit2.getModel().getSelectedItem());
            displayedCriteria[2] = PlacementParameterSet.criterionUID((String) cbxCrit3.getModel().getSelectedItem());
            displayedCriteria[3] = PlacementParameterSet.criterionUID((String) cbxCrit4.getModel().getSelectedItem());
        } else {
            PlacementParameterSet displayedPPS = null;
            if (tournament != null && tournament.isOpen()) {
                displayedPPS = tournament.getTournamentParameterSet().getPlacementParameterSet();
                displayedCriteria[0] = displayedPPS.getPlaCriteria()[0];
                displayedCriteria[1] = displayedPPS.getPlaCriteria()[1];
                displayedCriteria[2] = displayedPPS.getPlaCriteria()[2];
                displayedCriteria[3] = displayedPPS.getPlaCriteria()[3];
            }
        }
    }

    private void updateStandingsComponents() throws RemoteException {
        int numberOfDisplayedRounds = 9;
        if (tournament == null || !tournament.isOpen()) {
            this.pnlIntStandings.setVisible(false);
            return;
        }

        if (this.tpnGotha.getSelectedComponent() != pnlStandings) {
            return;
        }
        this.pnlIntStandings.setVisible(true);
        int nbRounds = tournament.getTournamentParameterSet().getGeneralParameterSet().getNumberOfRounds();
        if (displayedRoundNumber > nbRounds - 1) {
            displayedRoundNumber = nbRounds - 1;
        }
        this.spnRoundNumber.setValue(displayedRoundNumber + 1);

        this.rdbCurrentPS.getModel().setSelected(!bDisplayTemporaryParameterSet);
        this.cbxCrit1.setEnabled(bDisplayTemporaryParameterSet);
        this.cbxCrit2.setEnabled(bDisplayTemporaryParameterSet);
        this.cbxCrit3.setEnabled(bDisplayTemporaryParameterSet);
        this.cbxCrit4.setEnabled(bDisplayTemporaryParameterSet);

        this.cbxCrit1.getModel().setSelectedItem(PlacementParameterSet.criterionLongName(displayedCriteria[0]));
        this.cbxCrit2.getModel().setSelectedItem(PlacementParameterSet.criterionLongName(displayedCriteria[1]));
        this.cbxCrit3.getModel().setSelectedItem(PlacementParameterSet.criterionLongName(displayedCriteria[2]));
        this.cbxCrit4.getModel().setSelectedItem(PlacementParameterSet.criterionLongName(displayedCriteria[3]));

        // Define displayedTPS
        TournamentParameterSet tps = tournament.getTournamentParameterSet();
        TournamentParameterSet displayedTPS = new TournamentParameterSet(tps);
//        GeneralParameterSet displayedGPS = displayedTPS.getGeneralParameterSet();
        PlacementParameterSet displayedPPS = displayedTPS.getPlacementParameterSet();
        displayedPPS.setPlaCriteria(displayedCriteria);

        lastDisplayedStandingsUpdateTime = tournament.getCurrentTournamentTime();
        ArrayList<ScoredPlayer> alOrderedScoredPlayers = new ArrayList<ScoredPlayer>();
        try {
            alOrderedScoredPlayers = tournament.orderedScoredPlayersList(displayedRoundNumber, displayedTPS.getPlacementParameterSet());
            // Eliminate non-players
            alOrderedScoredPlayers = eliminateNonImpliedPlayers(alOrderedScoredPlayers);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        String[][] hG = ScoredPlayer.halfGamesStrings(alOrderedScoredPlayers, displayedRoundNumber, displayedTPS);

        tblStandings.clearSelection();
        tblStandings.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

        DefaultTableColumnModel columnModel = (DefaultTableColumnModel) tblStandings.getColumnModel();

        ((DefaultTableCellRenderer) tblStandings.getTableHeader().getDefaultRenderer()).setHorizontalAlignment(SwingConstants.LEFT);

        columnModel.getColumn(PL_COL).setHeaderValue("PL.");

        columnModel.getColumn(NAME_COL).setHeaderValue("Name");
        columnModel.getColumn(RANK_COL).setHeaderValue("Rk");

        columnModel.getColumn(NBW_COL).setHeaderValue("NBW");

        for (int r = 0; r < Gotha.MAX_NUMBER_OF_ROUNDS; r++) {
            columnModel.getColumn(ROUND0_RESULT_COL + r).setHeaderValue("R" + (r + 1));

        }
        for (int c = 0; c < PlacementParameterSet.PLA_MAX_NUMBER_OF_CRITERIA; c++) {
            columnModel.getColumn(CRIT0_COL + c).setHeaderValue(PlacementParameterSet.criterionShortName(displayedCriteria[c]));
        }
        columnModel.getColumn(PL_COL).setPreferredWidth(30);
        columnModel.getColumn(NAME_COL).setPreferredWidth(110);
        columnModel.getColumn(RANK_COL).setPreferredWidth(30);
        columnModel.getColumn(NBW_COL).setPreferredWidth(20);
        for (int r = 0; r <= displayedRoundNumber - numberOfDisplayedRounds; r++) {
            columnModel.getColumn(ROUND0_RESULT_COL + r).setMinWidth(2);
            columnModel.getColumn(ROUND0_RESULT_COL + r).setPreferredWidth(2);
        }
        for (int r = Math.max(displayedRoundNumber - numberOfDisplayedRounds + 1, 0); r <= displayedRoundNumber; r++) {
            columnModel.getColumn(ROUND0_RESULT_COL + r).setPreferredWidth(50);
        }
        for (int r = displayedRoundNumber + 1; r <= Gotha.MAX_NUMBER_OF_ROUNDS; r++) {
            columnModel.getColumn(ROUND0_RESULT_COL + r).setMinWidth(0);
            columnModel.getColumn(ROUND0_RESULT_COL + r).setPreferredWidth(0);
        }

        for (int c = 0; c < PlacementParameterSet.PLA_MAX_NUMBER_OF_CRITERIA; c++) {
            if (displayedPPS.getPlaCriteria()[c] == PlacementParameterSet.PLA_CRIT_NUL) {
                columnModel.getColumn(CRIT0_COL + c).setMinWidth(0);
                columnModel.getColumn(CRIT0_COL + c).setPreferredWidth(0);
            } else {
                columnModel.getColumn(CRIT0_COL + c).setPreferredWidth(40);
            }
        }

        DefaultTableModel model = (DefaultTableModel) tblStandings.getModel();
        model.setRowCount(alOrderedScoredPlayers.size());
        for (int iSP = 0; iSP < alOrderedScoredPlayers.size(); iSP++) {
            int iCol = 0;
            ScoredPlayer sp = alOrderedScoredPlayers.get(iSP);
            model.setValueAt("" + (iSP + 1), iSP, iCol++);
            model.setValueAt(sp.fullName(), iSP, iCol++);
            model.setValueAt(Player.convertIntToKD(sp.getRank()), iSP, iCol++);
            model.setValueAt(sp.formatScore(PlacementParameterSet.PLA_CRIT_NBW, this.displayedRoundNumber), iSP, iCol++);
            for (int r = 0; r <= displayedRoundNumber; r++) {
                model.setValueAt((hG[r][iSP]), iSP, iCol++);
            }
            for (int r = displayedRoundNumber + 1; r < Gotha.MAX_NUMBER_OF_ROUNDS; r++) {
                model.setValueAt("", iSP, iCol++);
            }
            for (int c = 0; c < displayedCriteria.length; c++) {
                model.setValueAt(sp.formatScore(displayedCriteria[c], this.displayedRoundNumber), iSP, iCol++);
            }
        }

        java.util.Date dh = new java.util.Date(lastDisplayedStandingsUpdateTime);
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

        String strTime = sdf.format(dh);
        lblUpdateTime.setText("updated at : " + strTime);
    }

    private ArrayList<ScoredPlayer> eliminateNonImpliedPlayers(ArrayList<ScoredPlayer> alSP) {
        Hashtable<Player, Boolean> htPlayersImplied = new Hashtable<Player, Boolean>();
        try {
            ArrayList<Game> alG = tournament.gamesList();
            for (Game g : alG) {
                Player wP = g.getWhitePlayer();
                htPlayersImplied.put(wP, true);
                Player bP = g.getBlackPlayer();
                htPlayersImplied.put(bP, true);
            }
            for (int r = 0; r < Gotha.MAX_NUMBER_OF_ROUNDS; r++) {
                Player byeP = tournament.getByePlayer(r);
                if (byeP != null) {
                    htPlayersImplied.put(byeP, true);
                }
            }
            for (Iterator<ScoredPlayer> it = alSP.iterator(); it.hasNext();) {
                ScoredPlayer sP = it.next();
                Boolean b = htPlayersImplied.get(sP);
                if (b == null) {
                    continue;
                }
                if (!b) {
                    it.remove();
                }
            }

        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }
        return alSP;
    }

    private void updateControlPanel() throws RemoteException {
        if (tournament == null || !tournament.isOpen()) {
            this.pnlIntControlPanel.setVisible(false);
            return;
        }

        this.pnlIntControlPanel.setVisible(true);

        TournamentParameterSet tps = tournament.getTournamentParameterSet();
        DefaultTableModel model = (DefaultTableModel) tblControlPanel.getModel();
        while (model.getRowCount() > 0) {
            model.removeRow(0);
        }
        ArrayList<Player> alPlayers = tournament.playersList();

        for (int r = 0; r < tps.getGeneralParameterSet().getNumberOfRounds(); r++) {
            // Number of participants
            int nbParticipants = 0;
            for (Player p : alPlayers) {
                if (p.getParticipating()[r]) {
                    nbParticipants++;
                    // Assigned players, games, etc.
                }
            }
            ArrayList<Game> alGames = tournament.gamesList(r);
            int nbGames = alGames.size();
            int nbAssignedPlayers = 2 * nbGames;
            if (tournament.getByePlayer(r) != null) {
                nbAssignedPlayers++;
            }
            int nbEntResults = 0;
            for (Game g : alGames) {
                int result = g.getResult();
                if (result != Game.RESULT_UNKNOWN) {
                    nbEntResults++;
                }
            }

            Vector<String> row = new Vector<String>();
            row.add("" + (r + 1));

            row.add("" + nbParticipants);

            row.add("" + nbAssignedPlayers);
            if (nbAssignedPlayers != nbParticipants) {
                this.cpTableCellRenderer.cpWarning[r][2] = true;
            } else {
                this.cpTableCellRenderer.cpWarning[r][2] = false;
            }

            row.add("" + nbEntResults + "/" + nbGames);
            if (nbEntResults != nbGames) {
                this.cpTableCellRenderer.cpWarning[r][3] = true;
            } else {
                this.cpTableCellRenderer.cpWarning[r][3] = false;
            }

            model.addRow(row);
        }
//        tblControlPanel.setRowSelectionAllowed(true);
        tblControlPanel.clearSelection();
//        tblControlPanel.addRowSelectionInterval(2, 2);
//        tblControlPanel.addRowSelectionInterval(4, 4);
        tblControlPanel.changeSelection(1, 2, true, false);
        tblControlPanel.changeSelection(5, 1, true, false);



        //tblStandings.repaint();
        this.lblWarningPRE.setText("");

        int nbPreliminary = 0;
        int nbFinal = 0;
        for (Player p : alPlayers) {
            if (p.getRegisteringStatus().compareTo("PRE") == 0) {
                nbPreliminary++;

            }
            if (p.getRegisteringStatus().compareTo("FIN") == 0) {
                nbFinal++;

            }
        }
        if (nbPreliminary == 1) {
            lblWarningPRE.setText("Warning!" + nbPreliminary
                    + "player has a Preliminary registering status");
        }
        if (nbPreliminary > 1) {
            lblWarningPRE.setText("Warning!" + nbPreliminary
                    + "players have a Preliminary registering status");
        }
    }

    private void mniSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniSaveActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        try {
            String fileName = tournament.getKeyName();
            saveTournament(new File(Gotha.tournamentDirectory, fileName));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_mniSaveActionPerformed

    /**
     *  if necessary, saves the current tournament
     *  @return false if operation has been cancelled  
     */
    private boolean saveCurrentTournamentIfNecessary() {
        if (Gotha.runningMode == Gotha.RUNNING_MODE_CLI) {
            return false;
        }
        try {
            if (tournament == null || !tournament.isOpen()) {
                return true;
            }
            if (!tournament.isChangeSinceLastSave()) {
                return true;
            }
            int response = JOptionPane.showConfirmDialog(this, "Do you want to save current tournament ?",
                    "Message", JOptionPane.YES_NO_CANCEL_OPTION);
            if (response == JOptionPane.CANCEL_OPTION) {
                return false;
            }
            if (response == JOptionPane.YES_OPTION) {
                String fileName = tournament.getKeyName();
                saveTournament(new File(Gotha.tournamentDirectory, fileName));
                return true;
            }

        } catch (HeadlessException ex) {
            ex.printStackTrace();
            return false;
        } catch (RemoteException ex) {
            ex.printStackTrace();
            return false;
        }
        return true;
    }

    private void saveTournament(File f) {
        TournamentInterface t = tournament;
        saveTournament(t, f);
    }

    private void saveTournament(TournamentInterface t, File f) {
        // if current extension is not .gth, add .gth
        String suffix = null;
        String s = f.getName();
        int i = s.lastIndexOf('.');
        if (i > 0 && i < s.length() - 1) {
            suffix = s.substring(i + 1).toLowerCase();
        }
        try {
            if (suffix == null || !suffix.equals("gth")) {
                f = new File(f.getCanonicalPath() + ".gth");

            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        try {
            FileOutputStream fos = new FileOutputStream(f);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(t);
            oos.flush();
            oos.close();
            t.setChangeSinceLastSave(false);
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        // update Preferences
        this.addRecentTournament(f.getAbsolutePath());

        this.tournamentChanged();
    }

    private void mniHelpAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniHelpAboutActionPerformed
        javax.swing.JTextArea txa = new javax.swing.JTextArea(Gotha.getCopyLeftText() + Gotha.getThanksToText());
        txa.setFont(new Font("Tahoma", Font.PLAIN, 11));
        JOptionPane.showMessageDialog(this, txa, "OpenGotha",
                JOptionPane.INFORMATION_MESSAGE, new ImageIcon(Gotha.getIconImage()));
    }//GEN-LAST:event_mniHelpAboutActionPerformed

    private void mniPlayersManagerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniPlayersManagerActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        try {
            JFrame jfr = new JFrPlayersManager(tournament);
            jfr.setVisible(true);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }//GEN-LAST:event_mniPlayersManagerActionPerformed

    private void mniSaveAsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniSaveAsActionPerformed
        try {
            if (tournament == null || !tournament.isOpen()) {
                JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (HeadlessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        JFileChooser fileChoice = new JFileChooser(Gotha.tournamentDirectory);
        fileChoice.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fileChoice.setDialogType(JFileChooser.SAVE_DIALOG);

        String shortName = "TournamentShortName";
        try {
            shortName = tournament.getKeyName();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        fileChoice.setSelectedFile(new File(shortName + ".gth"));

        MyFileFilter mff = new MyFileFilter(new String[]{"gth"},
                "Gotha Files(*.gth)");
        fileChoice.addChoosableFileFilter(mff);
        int result = fileChoice.showSaveDialog(this);
        File f = null;
        if (result == JFileChooser.CANCEL_OPTION) {
            f = null;
        } else {
            f = fileChoice.getSelectedFile();
        }
        if (f == null) {
            return;
            // Keep tournamentDirectory
        }
        Gotha.tournamentDirectory = fileChoice.getCurrentDirectory();
        saveTournament(f);
    }//GEN-LAST:event_mniSaveAsActionPerformed

    private void mniOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniOpenActionPerformed
        File f = chooseAFile(Gotha.tournamentDirectory, "gth");
        if (f == null) {
            return;
        }
        try {
            openTournament(f);
            // update Preferences
            this.addRecentTournament(f.getAbsolutePath());
        } catch (FileNotFoundException ex) {
            JOptionPane.showMessageDialog(this, " File not found", "Message", JOptionPane.ERROR_MESSAGE);
//            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }
    }//GEN-LAST:event_mniOpenActionPerformed

private void mniRRActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniRRActionPerformed
    try {
        if (tournament == null || !tournament.isOpen()) {
            JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
            return;
        }
    } catch (HeadlessException ex) {
        ex.printStackTrace();
    } catch (RemoteException ex) {
        ex.printStackTrace();
    }
    try {
        JFrame jfr = new JFrGamesRR(tournament);
        jfr.setVisible(true);
    } catch (RemoteException ex) {
        ex.printStackTrace();
    }

}//GEN-LAST:event_mniRRActionPerformed

private void mniRMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniRMIActionPerformed
    JFrame jfr = new JFrToolsRMI();
    jfr.setVisible(true);
}//GEN-LAST:event_mniRMIActionPerformed

private void mniOpenGothaHelpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniOpenGothaHelpActionPerformed
    Gotha.displayGothaHelp("Starting OpenGotha");
}//GEN-LAST:event_mniOpenGothaHelpActionPerformed

// Very temporary 
private void mniExportXMLActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniExportXMLActionPerformed
    try {
        if (tournament == null || !tournament.isOpen()) {
            JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
            return;
        }
    } catch (HeadlessException ex) {
        ex.printStackTrace();
    } catch (RemoteException ex) {
        ex.printStackTrace();
    }

    File f = this.chooseAFileForExport(Gotha.exportXMLDirectory, "xml");
    if (f == null) {
        return;
    }
    // Keep tournamentDirectory
    Gotha.exportXMLDirectory = f.getParentFile();

    ExternalTournamentDocument.generateXMLFile(tournament, f);


}//GEN-LAST:event_mniExportXMLActionPerformed

private void mniImportXMLActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniImportXMLActionPerformed
    try {
        if (tournament == null || !tournament.isOpen()) {
            JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
            return;
        }
    } catch (HeadlessException ex) {
        ex.printStackTrace();
    } catch (RemoteException ex) {
        ex.printStackTrace();
    }

    int w = 600;
    int h = 350;
    Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
    dlgImportXML.setBounds((dim.width - w) / 2, (dim.height - h) / 2, w, h);
    dlgImportXML.setTitle("Objects to import");
    dlgImportXML.setIconImage(Gotha.getIconImage());

    dlgImportXML.setVisible(true);


}//GEN-LAST:event_mniImportXMLActionPerformed

private void btnDlgImportXMLOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDlgImportXMLOKActionPerformed
    dlgImportXML.dispose();

    // From what file shall we import ?
    File f = chooseAFile(Gotha.runningDirectory, "xml");
    if (f == null) {
        return;
    }

    int nbImportedPlayers = 0;
    int nbNotImportedPlayers = 0;
    if (this.chkPlayers.isSelected()) {
        ArrayList<Player> alPlayers = ExternalTournamentDocument.importPlayersFromXMLFile(f);
        if (alPlayers == null) {
            JOptionPane.showMessageDialog(this, "No player could be imported", "Message", JOptionPane.ERROR_MESSAGE);
            return;
        }
        for (Player p : alPlayers) {
            try {
                tournament.addPlayer(p);
                nbImportedPlayers++;
            } catch (TournamentException ex) {
                // Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
                System.out.println("" + ex.getMessage());
            } catch (RemoteException ex) {
                Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        nbNotImportedPlayers = alPlayers.size() - nbImportedPlayers;
    }

    int nbImportedGames = 0;
    int nbNotImportedGames = 0;
    int nbReplacedGames = 0;
    int nbImportedByePlayers = 0;
    int nbReplacedByePlayers = 0;

    if (this.chkGames.isSelected()) {
        // import games
        int nbGamesBeforeImport = 0;
        try {
            nbGamesBeforeImport = tournament.gamesList().size();
        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }
        ArrayList<Game> alGames = ExternalTournamentDocument.importGamesFromXMLFile(f, tournament);
        if (alGames == null) {
            JOptionPane.showMessageDialog(this, "No game could be imported", "Message", JOptionPane.ERROR_MESSAGE);
            return;
        }

        for (Game g : alGames) {
            try {
                tournament.addGame(g);
                nbImportedGames++;
            } catch (TournamentException ex) {
                Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
            } catch (RemoteException ex) {
                Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        nbNotImportedGames = alGames.size() - nbImportedGames;

        int nbGamesAfterImport = 0;
        try {
            nbGamesAfterImport = tournament.gamesList().size();
        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }
        nbReplacedGames = nbImportedGames - (nbGamesAfterImport - nbGamesBeforeImport);

        // import bye palyers
        Player[] importedByePlayers = ExternalTournamentDocument.importByePlayersFromXMLFile(f, tournament);
        Player[] byePlayers = null;
        try {
            byePlayers = tournament.getByePlayers();
        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }
        for (int r = 0; r < byePlayers.length; r++) {
            if (importedByePlayers[r] == null) {
                continue;
            }
            nbImportedByePlayers++;
            if (byePlayers[r] != null) {
                nbReplacedByePlayers++;
            }
            try {
                tournament.assignByePlayer(importedByePlayers[r], r);
            } catch (RemoteException ex) {
                Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }
    if (this.chkTournamentParameters.isSelected()) {
        // import tournament parameters
        TournamentParameterSet tps = ExternalTournamentDocument.importTournamentParameterSetFromXMLFile(f);
        if (tps == null) {
            JOptionPane.showMessageDialog(this, "No parameter could be imported", "Message", JOptionPane.ERROR_MESSAGE);
            return;
        }
        try {
            tournament.setTournamentParameterSet(tps);
        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    try {
        tournament.updateNumberOfRoundsIfNecesary();
    } catch (RemoteException ex) {
        Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
    }

    try {
        tournament.setLastTournamentModificationTime(tournament.getCurrentTournamentTime());
        this.updateControlPanel();
        this.updateStandingsComponents();
    } catch (RemoteException ex) {
        Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
    }


    // Report about imported objects
    String strReport = "" + nbImportedPlayers + " players have been imported";
    if (nbNotImportedPlayers > 0) {
        strReport += "\n" + nbNotImportedPlayers + " players could not be imported.";
    }

    strReport += "\n\n" + nbImportedGames + " games have been imported.";
    if (nbNotImportedGames > 0) {
        strReport = "\n" + nbNotImportedGames + " games could not be imported.";
    }
    if (nbReplacedGames > 0) {
        strReport += "\n" + nbReplacedGames + " games have been replaced.";
    }

    strReport += "\n\n" + nbImportedByePlayers + " bye players have been imported.";
    if (nbReplacedByePlayers > 0) {
        strReport += "\n" + nbReplacedByePlayers + " bye players have been replaced.";
    }

    JOptionPane.showMessageDialog(this, strReport, "Message", JOptionPane.INFORMATION_MESSAGE);




}//GEN-LAST:event_btnDlgImportXMLOKActionPerformed

private void btnDlgImportXMLCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDlgImportXMLCancelActionPerformed
    this.dlgImportXML.dispose();
}//GEN-LAST:event_btnDlgImportXMLCancelActionPerformed

private void spnRoundNumberStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnRoundNumberStateChanged
    int demandedRN = (Integer) (spnRoundNumber.getValue()) - 1;
    this.demandedDisplayedRoundNumberHasChanged(demandedRN);
}//GEN-LAST:event_spnRoundNumberStateChanged

private void btnHelpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnHelpActionPerformed
    Gotha.displayGothaHelp("Create a new tournament");
}//GEN-LAST:event_btnHelpActionPerformed

private void btnSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSearchActionPerformed
    String strSearchPlayer = this.txfSearchPlayer.getText().toLowerCase();
    if (strSearchPlayer.length() == 0) {
        tblStandings.clearSelection();
        return;
    }
    TableModel model = tblStandings.getModel();

    int rowNumber = -1;
    int startRow = tblStandings.getSelectedRow() + 1;
    int nbRows = model.getRowCount();
    for (int iR = 0; iR < nbRows; iR++) {
        int row = (startRow + iR) % nbRows;
        String str = (String) model.getValueAt(row, NAME_COL);
        str = str.toLowerCase();
        if (str.indexOf(strSearchPlayer) < 0) {
            continue;
        }
        // OK! Found
        rowNumber = row;
        break;
    }

    tblStandings.clearSelection();
    if (rowNumber == -1) {
        JOptionPane.showMessageDialog(this,
                "No player with the specified name was found in the Standings table ",
                "Message", JOptionPane.ERROR_MESSAGE);
    } else {
        tblStandings.setRowSelectionAllowed(true);
        tblStandings.clearSelection();
        tblStandings.addRowSelectionInterval(rowNumber, rowNumber);

        Rectangle rect = tblStandings.getCellRect(rowNumber, 0, true);
        tblStandings.scrollRectToVisible(rect);
    }

    tblStandings.repaint();
}//GEN-LAST:event_btnSearchActionPerformed

private void mniImportH9ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mniImportH9ActionPerformed
    try {
        if (tournament == null || !tournament.isOpen()) {
            JOptionPane.showMessageDialog(this, "No currently open tournament", "Message", JOptionPane.ERROR_MESSAGE);
            return;
        }
    } catch (HeadlessException ex) {
        ex.printStackTrace();
    } catch (RemoteException ex) {
        ex.printStackTrace();
    }

    File f = chooseAFile(Gotha.runningDirectory, "h9");
    if (f == null) {
        return;
    }
    ArrayList<Player> alPlayers = new ArrayList<Player>();
    ArrayList<Game> alGames = new ArrayList<Game>();
    try{
        ExternalTournamentDocument.importPlayersAndGamesFromH9File(f, alPlayers, alGames);
    }
    catch(Exception e){
        JOptionPane.showMessageDialog(this, "Errors occured in reading " + f.getName()
                + "\nImport process has been aborted", "Message", JOptionPane.ERROR_MESSAGE);
        return;
    }
    int nbErrors = 0;
    for (Player p : alPlayers) {
        try {
            tournament.addPlayer(p);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        } catch (TournamentException te) {
            nbErrors++;
            if (nbErrors <= 3) {
                JOptionPane.showMessageDialog(this, te.getMessage(), "Message", JOptionPane.ERROR_MESSAGE);
            }
            if (nbErrors == 4) {
                JOptionPane.showMessageDialog(this, "More than 3 errors have been detected", "Message", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
    if (nbErrors > 0) {
        JOptionPane.showMessageDialog(this, "Due to errors on players, games have not been imported", "Message", JOptionPane.ERROR_MESSAGE);
    } else {
        for (Game g : alGames) {
            try {
                tournament.addGame(g);
            } catch (RemoteException ex) {
                ex.printStackTrace();
            } catch (TournamentException ex) {
                ex.printStackTrace();
            }
        }
    }
    try {
        tournament.updateNumberOfRoundsIfNecesary();
    } catch (RemoteException ex) {
        Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
    }

    this.tournamentChanged();
}//GEN-LAST:event_mniImportH9ActionPerformed

private void lblSoftpediaMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_lblSoftpediaMouseClicked
    java.awt.Desktop desktop = java.awt.Desktop.getDesktop();

    try {
            java.net.URI uri = new java.net.URI("http://mac.softpedia.com/get/Games/OpenGotha.shtml");
            desktop.browse(uri);
        } catch (IOException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        } catch (URISyntaxException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }

}//GEN-LAST:event_lblSoftpediaMouseClicked

    private File chooseAFile(File path, String extension) {
        JFileChooser fileChoice = new JFileChooser(path);
        fileChoice.setFileSelectionMode(JFileChooser.FILES_ONLY);
        MyFileFilter mff = new MyFileFilter(new String[]{extension}, "*." + extension);
        fileChoice.addChoosableFileFilter(mff);
        int result = fileChoice.showOpenDialog(this);
        if (result == JFileChooser.CANCEL_OPTION) {
            return null;
        } else {
            return fileChoice.getSelectedFile();
        }
    }

    private File chooseAFileForExport(File path, String extension) {
        JFileChooser fileChoice = new JFileChooser(path);

        fileChoice.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fileChoice.setDialogType(JFileChooser.SAVE_DIALOG);
        String keyName = "TournamentShortName";
        try {
            keyName = tournament.getKeyName();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        fileChoice.setSelectedFile(new File(path, keyName + "." + extension));

        MyFileFilter mff = new MyFileFilter(new String[]{extension}, "*." + extension);
        fileChoice.addChoosableFileFilter(mff);
        int result = fileChoice.showSaveDialog(this);
        if (result == JFileChooser.CANCEL_OPTION) {
            return null;
        } else {
            return fileChoice.getSelectedFile();
        }
    }

    private void openTournament(File f) throws FileNotFoundException {
        if (!saveCurrentTournamentIfNecessary()) {
            return;
        }

        TournamentInterface t = Gotha.getTournamentFromFile(f);
        if (t == null){
            String strMessage = "Some problem occured with file : " + f.getName();
            strMessage += "\nThe corresponding tournament has not been opened";
            JOptionPane.showMessageDialog(this, strMessage, "Message", JOptionPane.ERROR_MESSAGE);
            return;
        }
        // Check if a tournament with same name exists (Server mode only)
        if (Gotha.runningMode == Gotha.RUNNING_MODE_SRV) {
            String tKN = null;
            try {
                tKN = t.getKeyName();
            } catch (RemoteException ex) {
                Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
            }
            TournamentInterface oldT = GothaRMIServer.getTournament(tKN);
            if (oldT != null) {
                String strMessage = tKN + " is already opened on this server";
                strMessage += "\nIt will not be opened again";
                JOptionPane.showMessageDialog(this, strMessage, "Message", JOptionPane.WARNING_MESSAGE);
                return;
            }
        }

        if (tournament != null) {
            closeTournament();
        }
        tournament = t;


        // If we are in Server mode, then worry about adding it to registry
        if (Gotha.runningMode == Gotha.RUNNING_MODE_SRV) {
            GothaRMIServer.addTournament(tournament);
        }

        try {
            tournament.setLastTournamentModificationTime(tournament.getCurrentTournamentTime());
        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            this.displayedRoundNumber = tournament.presumablyCurrentRoundNumber();
            this.tournamentChanged();
        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private void closeTournament() {
        if (tournament == null) {
            return;
        }
        tournament = null;
        this.tournamentChanged();

    }

    public void tournamentChanged() {
        updateTitle();
        if (tournament == null) {
            try {
                this.updateDisplayCriteria();
                this.updateStandingsComponents();
                this.updateControlPanel();
            } catch (RemoteException ex) {
                Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
            }
            return;
        }
        try {
            tournament.setLastTournamentModificationTime(tournament.getCurrentTournamentTime());
        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }

        updateAllViews();
    }

    private void updateAllViews() {

        try {
            this.lastComponentsUpdateTime = tournament.getCurrentTournamentTime();
            if (tournament.tournamentType() == TournamentParameterSet.TYPE_MACMAHON) {
                this.mniMMGroups.setEnabled(true);
            } else {
                this.mniMMGroups.setEnabled(false);
            }
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }

        updateTitle();

        if (this.tpnGotha.getSelectedComponent() == pnlStandings) {
            try {
                this.updateDisplayCriteria();
                this.updateStandingsComponents();

            } catch (RemoteException ex) {
                ex.printStackTrace();
            }
        }
        if (this.tpnGotha.getSelectedComponent() == pnlControlPanel) {
            try {
                this.updateControlPanel();
            } catch (RemoteException ex) {
                ex.printStackTrace();
            }
        }

    }

    private void demandedDisplayedRoundNumberHasChanged(int demandedRN) {
        int numberOfRounds = 0;
        try {
            numberOfRounds = tournament.getTournamentParameterSet().getGeneralParameterSet().getNumberOfRounds();
        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }
        if (demandedRN < 0 || demandedRN >= numberOfRounds) {
            spnRoundNumber.setValue(displayedRoundNumber + 1);
            return;
        }
        if (demandedRN == displayedRoundNumber) {
            return;
        }

        displayedRoundNumber = demandedRN;
        try {
            updateStandingsComponents();
        } catch (RemoteException ex) {
            Logger.getLogger(JFrGotha.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnDlgImportXMLCancel;
    private javax.swing.JButton btnDlgImportXMLOK;
    private javax.swing.JButton btnDlgNewCancel;
    private javax.swing.JButton btnDlgNewOK;
    private javax.swing.JButton btnHelp;
    private javax.swing.JButton btnPrint;
    private javax.swing.JButton btnSearch;
    private javax.swing.JComboBox cbxCrit1;
    private javax.swing.JComboBox cbxCrit2;
    private javax.swing.JComboBox cbxCrit3;
    private javax.swing.JComboBox cbxCrit4;
    private javax.swing.JCheckBox chkGames;
    private javax.swing.JCheckBox chkPlayers;
    private javax.swing.JCheckBox chkTournamentParameters;
    private javax.swing.JDialog dlgImportXML;
    private javax.swing.JDialog dlgNew;
    private javax.swing.ButtonGroup grpPS;
    private javax.swing.ButtonGroup grpSystem;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel10;
    private javax.swing.JLabel jLabel11;
    private javax.swing.JLabel jLabel12;
    private javax.swing.JLabel jLabel13;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JSeparator jSeparator2;
    private javax.swing.JSeparator jSeparator3;
    private javax.swing.JSeparator jSeparator4;
    private javax.swing.JLabel lblFlowChart;
    private javax.swing.JLabel lblSoftpedia;
    private javax.swing.JLabel lblStandingsAfter;
    private javax.swing.JLabel lblTournamentPicture;
    private javax.swing.JLabel lblUpdateTime;
    private javax.swing.JLabel lblWarningPRE;
    private javax.swing.JMenuItem mniBuildTestTournament;
    private javax.swing.JMenuItem mniClose;
    private javax.swing.JMenuItem mniExit;
    private javax.swing.JMenuItem mniExportH9;
    private javax.swing.JMenuItem mniExportHTML;
    private javax.swing.JMenuItem mniExportPlayersCSV;
    private javax.swing.JMenuItem mniExportTou;
    private javax.swing.JMenuItem mniExportXML;
    private javax.swing.JMenuItem mniGamesOptions;
    private javax.swing.JMenuItem mniHelpAbout;
    private javax.swing.JMenuItem mniImportH9;
    private javax.swing.JMenuItem mniImportTou;
    private javax.swing.JMenuItem mniImportXML;
    private javax.swing.JMenuItem mniMMGroups;
    private javax.swing.JMenuItem mniNew;
    private javax.swing.JMenuItem mniOpen;
    private javax.swing.JMenuItem mniOpenGothaHelp;
    private javax.swing.JMenuItem mniPageSetup;
    private javax.swing.JMenuItem mniPair;
    private javax.swing.JMenuItem mniPlayersManager;
    private javax.swing.JMenuItem mniPlayersQuickCheck;
    private javax.swing.JMenuItem mniPrint;
    private javax.swing.JMenuItem mniRMI;
    private javax.swing.JMenuItem mniRR;
    private javax.swing.JMenuItem mniResults;
    private javax.swing.JMenuItem mniSave;
    private javax.swing.JMenuItem mniSaveAs;
    private javax.swing.JMenuItem mniTournamentOptions;
    private javax.swing.JMenu mnuExport;
    private javax.swing.JMenu mnuGames;
    private javax.swing.JMenu mnuHelp;
    private javax.swing.JMenu mnuImport;
    private javax.swing.JMenuBar mnuMain;
    private javax.swing.JMenu mnuOpenRecent;
    private javax.swing.JMenu mnuOptions;
    private javax.swing.JMenu mnuPlayers;
    private javax.swing.JMenu mnuTools;
    private javax.swing.JMenu mnuTournament;
    private javax.swing.JPanel pnlControlPanel;
    private javax.swing.JPanel pnlIdentification;
    private javax.swing.JPanel pnlIntControlPanel;
    private javax.swing.JPanel pnlIntStandings;
    private javax.swing.JPanel pnlObjectsToImport;
    private javax.swing.JPanel pnlPS;
    private javax.swing.JPanel pnlStandings;
    private javax.swing.JPanel pnlSystem;
    private javax.swing.JPanel pnlWelcome;
    private javax.swing.JRadioButton rdbCurrentPS;
    private javax.swing.JRadioButton rdbMacMahon;
    private javax.swing.JRadioButton rdbSwiss;
    private javax.swing.JRadioButton rdbSwissCat;
    private javax.swing.JRadioButton rdbTemporaryPS;
    private javax.swing.JScrollPane scpControlPanel;
    private javax.swing.JScrollPane scpStandings;
    private javax.swing.JSpinner spnRoundNumber;
    private javax.swing.JTable tblControlPanel;
    private javax.swing.JTable tblStandings;
    private javax.swing.JTabbedPane tpnGotha;
    private javax.swing.JTextField txfBeginDate;
    private javax.swing.JTextField txfLocation;
    private javax.swing.JTextField txfName;
    private javax.swing.JTextField txfNumberOfRounds;
    private javax.swing.JTextField txfSearchPlayer;
    private javax.swing.JTextField txfShortName;
    // End of variables declaration//GEN-END:variables
}

class MyFileFilter extends FileFilter {

    String[] suffixes;
    String description;

    public MyFileFilter(String[] suffixes, String description) {
        for (int i = 0; i < suffixes.length; i++) {
            this.suffixes = suffixes;
            this.description = description;
        }
    }

    boolean belongs(String suffix) {
        for (int i = 0; i < suffixes.length; i++) {
            if (suffix.equals(suffixes[i])) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean accept(File f) {
        if (f.isDirectory()) {
            return true;
        }
        String suffix = null;
        String s = f.getName();
        int i = s.lastIndexOf('.');
        if (i > 0 && i < s.length() - 1) {
            suffix = s.substring(i + 1).toLowerCase();
        }
        return suffix != null && belongs(suffix);
    }

    @Override
    public String getDescription() {
        return description;
    }
}

class StandingsTableCellRenderer extends JLabel implements TableCellRenderer {
    // This method is called each time a cell in a column
    // using this renderer needs to be rendered.

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int rowIndex, int colIndex) {
        TableModel model = table.getModel();
        setText("" + model.getValueAt(rowIndex, colIndex));
        if (isSelected) {
            setFont(new Font("Arial", Font.BOLD, 11));
        } else {
            setFont(new Font("Arial", Font.PLAIN, 10));
        }
        return this;
    }
}

class ControlPanelTableCellRenderer extends JLabel implements TableCellRenderer {
    // Assigned players will be in column 2; Entered results will be in column 3;

    protected boolean[][] cpWarning = new boolean[Gotha.MAX_NUMBER_OF_ROUNDS][4];

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int rowIndex, int colIndex) {
        TableModel model = table.getModel();
        setText("" + model.getValueAt(rowIndex, colIndex));
        if (cpWarning[rowIndex][colIndex]) {
            this.setForeground(Color.red);
        } else {
            setForeground(Color.black);
        }
        return this;
    }
}
